home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / Papers / Garrison / Code / SchmoozingExamples / ThreadedServer.m < prev   
Encoding:
Text File  |  2001-06-23  |  5.2 KB  |  143 lines

  1. //
  2. //  ThreadedServer.m
  3. //  SchmoozingExamples
  4. //
  5. //  Created by garrison on Fri Apr 20 2001.
  6. //  Copyright (c) 2001 Standard Orbit Software, LLC. All rights reserved.
  7. //
  8. //  Permission is granted to use this code for any purpose, at your own risk.
  9. //  No warranties are expressed or implied.
  10. //
  11.  
  12. /* An Algorithm for a Concurrent Server [Comer93]
  13.  
  14. Master 1) Create a socket for the server and bind it to the well known port 
  15.           for the service being offered.
  16. Master 2) Establishing a listener on the socket.
  17. Master 3) Repeatedly accept incoming requests and create new slaves to handle the response.
  18. Slave 1) Receive a connection request/socket upon creation.
  19. Slave 2) Interact with the client using the socket, reading requests and sending back replies.
  20. Slave 3) Close the connection and exit.  The slave exits after handling all requests 
  21.          from one client.
  22. */
  23.  
  24. #import "ThreadedServer.h"
  25.  
  26. #import <OmniNetworking/OmniNetworking.h>
  27. #import "Connection.h"
  28.  
  29. @implementation ThreadedServer
  30.  
  31. - (id) initWithLocalPort:(unsigned short) aPort
  32. {
  33.     self = [super init];
  34.     
  35.     if ( self )
  36.     {
  37.         NS_DURING {
  38.             
  39.             listeningSocket = [[ONTCPSocket tcpSocket] retain];
  40.             // Master Step 1. Create an ONTCPSocket for the server.
  41.             
  42.             [listeningSocket startListeningOnLocalPort:aPort allowingAddressReuse:YES];
  43.             // Master Step 2.
  44.             // Start socket listening on the well known port.  Allowing address reuse is
  45.             // helpful while debugging (it prevents a port from getting locked up if your
  46.             // app crashes without closing the socket).
  47.             
  48.             NSLog(@"Listening for connections on host %@:%d", [ONHost localHostname], aPort);
  49.         }
  50.         NS_HANDLER {
  51.             // Handle potential exceptions.
  52.             NSLog(@"%@ raised while starting the server: %@", 
  53.                 [localException name], localException);
  54.             [listeningSocket release];
  55.             return nil;
  56.         }
  57.         NS_ENDHANDLER
  58.     }
  59.         
  60.     return self;
  61. }
  62.  
  63.  
  64. - (void) dealloc
  65. {
  66.     [listeningSocket release];
  67.     [super dealloc];
  68. }
  69.  
  70.  
  71. - (void) run
  72. {
  73.     // This method implements a concurrent server using threads.  A new client
  74.     // connection object is created for each accepted connection.  A new
  75.     // thread is detached to then run the client connection's processing method.
  76.     
  77.     ONTCPSocket *connectionSocket = nil;
  78.     Connection *someClient = nil;
  79.     unsigned short connectionCount = 0;
  80.     
  81.     // 'connectionSocket' will hold the accepted connection, leaving 
  82.     // the listening socket free to continue listening.
  83.     // 'someClient' is an object of our own custom class for handling
  84.     // connections to our server.
  85.     // 'connectionCount' holds a count of connections accepted, just to
  86.     // provide some feedback in the spartan UI.
  87.  
  88.     NSLog(@"Threaded Concurrent Server");
  89.     
  90.     do 
  91.     {
  92.         NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
  93.  
  94.         NS_DURING 
  95.         {            
  96.             NSLog(@"Main thread listening for next connection");
  97.             
  98.             connectionSocket = [listeningSocket acceptConnectionOnNewSocket];
  99.             // Master Step 3.  Accept the next incoming connection.  The main
  100.             // thread will block until a connection request is received.
  101.             
  102.             connectionCount += 1;
  103.             // Increment the accepted connection count
  104.  
  105.             NSLog(@"Accepted connection %d from host %@", connectionCount, 
  106.                     [[connectionSocket remoteAddressHost] hostname]);
  107.             
  108.             someClient = [[Connection alloc] initWithConnectedSocket:connectionSocket];
  109.             // Slave Step 1.  Receive the accepted connection when our slave is
  110.             // initialized.  The role of Slave is played by 'someClient'.
  111.             
  112.             NSLog(@"Detaching a thread to process the connection");
  113.             [NSThread detachNewThreadSelector:@selector(processConnection)  
  114.                                 toTarget:someClient  withObject:nil];
  115.             // Slave Step 2.  Spawn off a new thread to run our server's interaction
  116.             // with the client.
  117.             
  118.             [loopPool release];
  119.             // Since detachNewThreadSelector: will retain our Connection object, 
  120.             // (and Connection retained the accepted socket object on init), we can
  121.             // safely release the loop pool (thereby removing our responsibility 
  122.             // for these objects).  When the thread terminates, those objects
  123.             // will be released (and the socket will be closed).
  124.         }
  125.         
  126.         NS_HANDLER 
  127.         {
  128.             NSLog(@"%@ raised during threaded server processing: %@", 
  129.                     [localException name], localException);
  130.             [loopPool release];
  131.             break;
  132.             // Close down the server loop if an error occurs.
  133.         }
  134.         NS_ENDHANDLER
  135.  
  136.     } while (1);
  137.     // Loop forever listening for and accepting connections.  As implemented here, the only way 
  138.     // the server will quit is if an exception is raised during execution.  You will want to add
  139.     // some additional means of gracefully bringing a server down (e.g. handling
  140.     // a SIGTERM or SIGHUP signal).
  141. }
  142. @end
  143.